/*
 * interfaz.c
 *
 *  Created on: 22/09/2011
 *      Author: utn_so
 */

#include "interfaz.h"
#include "fat_defs.h"
#include "fat.h"
#include "config.h"

extern struct bootsector bs;
extern struct stConfig config;
extern int32_t cantidadConexiones;
extern int32_t conexionesAbiertas;
extern pthread_mutex_t semaforoCantidadConexion;

unsigned char * obtenerBloque(int32_t numBloque)
{
	int socket = -1;


	socket = crearConexion();
	//	socket2 = crearConexion();

	unsigned char *bloque;

	//si el sockets fueron creados correctamente
	if(socket>0)
	{
		bloque = malloc(sizeof(char)*1024);
		memset(bloque, 0, 1024);

		///////////////////////////ENVIAR////////////////////////////////////////////////////
		//calcula el numero de los dos sectores (segun el bloque) y hace los dos pedidos a los chicos
		int32_t numSector = numBloque *2;
		int32_t nbytes = 0;
		unsigned char *sector = malloc(sizeof(char)*512);


		//obtengo primer sector
		stPedido *pedido = malloc(sizeof(stPedido));
		pedido->sector = numSector;
		pedido->tipoOperacion = LEER;
		pedido->socketPFS = -1;

		int32_t payloadlength = sizeof(stPedido);
		char *mensaje = malloc(payloadlength);
		memcpy(mensaje,pedido,payloadlength);
		char *paq = serializarNipc(LEER,mensaje,payloadlength);

		send(socket,paq,sizeof(PAQUETE_NIPC_CABECERA) + payloadlength, 0);
		free(paq);

		//obtengo segundo sector
		numSector++;
		pedido->sector = numSector;
		pedido->tipoOperacion = LEER;
		pedido->socketPFS = -1;

		memcpy(mensaje,pedido,payloadlength);
		paq = serializarNipc(LEER,mensaje,payloadlength);

		send(socket,paq,sizeof(PAQUETE_NIPC_CABECERA) + payloadlength, 0);

		free(paq);
		free(pedido);
		///////////////////////////FIN ENVIAR////////////////////////////////////////////////////

		///////////////////////////RECIBIR///////////////////////////////////////////////////////
		PAQUETE_NIPC_CABECERA *cabecera = (PAQUETE_NIPC_CABECERA*)malloc(sizeof(PAQUETE_NIPC_CABECERA));
		int32_t total;

		//int32_t *bytesRecibidos;
		stPedido *pedidoRta;


		if ((nbytes = recv(socket, cabecera, sizeof(PAQUETE_NIPC_CABECERA), MSG_WAITALL)) <= 0)
		{
			if(config.loguear == 1)
			{
				int pid = getpid();
				logMessage("obtenerBloque",pid,gettid(),2,"La cabecera recibida no es correcta.");
			}
		}
		else
		{
			pedidoRta = recibirDeSocket(socket, cabecera);

			if(pedidoRta->sector == (numSector-1))
			{
				memcpy(bloque, pedidoRta->contenido, 512);
			}
			else if(pedidoRta->sector == numSector)
			{
				memcpy(bloque+512, pedidoRta->contenido, 512);
			}
			free(pedidoRta);
		}

		stPedido *pedidoRta2;

		if ((nbytes = recv(socket, cabecera, sizeof(PAQUETE_NIPC_CABECERA), MSG_WAITALL)) <= 0)
		{
			if(config.loguear == 1)
			{
				int pid = getpid();
				logMessage("obtenerBloque",pid,gettid(),2,"La cabecera recibida no es correcta.");
			}
		}
		else
		{

			pedidoRta2 = recibirDeSocket(socket, cabecera);

			if(pedidoRta2->sector == (numSector-1))
			{
				memcpy(bloque, pedidoRta2->contenido, 512);
			}
			else if(pedidoRta2->sector == numSector)
			{
				memcpy(bloque+512, pedidoRta2->contenido, 512);
			}
			free(pedidoRta2);
		}

		///////////////////////////FIN RECIBIR///////////////////////////////////////////////////////
		free(sector);
		free(cabecera);
		free(mensaje);


		cerrarConexion(socket);

	}
	else
	{
		//	todo loguear error


	}

	return bloque;

}


int32_t escribirBloque(int32_t numBloque, unsigned char *contenido)
{
	int32_t socket = -1;

	socket = crearConexion();


	if(socket>0)
	{
		///////////////////////////ENVIAR////////////////////////////////////////////////////
		int32_t nbytes = 0;
		int32_t numSector = numBloque *2;

		//escribo primer sector
		stPedido *pedido = malloc(sizeof(stPedido));
		pedido->sector = numSector;
		pedido->tipoOperacion = ESCRIBIR;
		pedido->socketPFS = -1;
		memcpy(pedido->contenido, contenido, 512);

		int32_t payloadlength = sizeof(stPedido);
		char *mensaje = malloc(payloadlength);
		memcpy(mensaje,pedido,payloadlength);
		char *paq = serializarNipc(ESCRIBIR,mensaje,payloadlength);

		//ACA DEBERIA MANEJAR EL POOL DE CONEXIONES, VER SI TENGO DSPONIBILIDAD Y MANDAR
		send(socket,paq,sizeof(PAQUETE_NIPC_CABECERA) + payloadlength, 0);

		numSector++;

		//escribo segundo sector
		pedido->sector = numSector;
		pedido->tipoOperacion = ESCRIBIR;
		pedido->socketPFS = -1;
		memcpy(pedido->contenido, contenido+512, 512);

		memcpy(mensaje,pedido,payloadlength);
		paq = serializarNipc(ESCRIBIR,mensaje,payloadlength);

		//ACA DEBERIA MANEJAR EL POOL DE CONEXIONES, VER SI TENGO DSPONIBILIDAD Y MANDAR
		send(socket,paq,sizeof(PAQUETE_NIPC_CABECERA) + payloadlength, 0);
		///////////////////////////FIN ENVIAR////////////////////////////////////////////////////

		///////////////////////////RECIBIR////////////////////////////////////////////////////
		PAQUETE_NIPC_CABECERA *cabecera = (PAQUETE_NIPC_CABECERA*)malloc(sizeof(PAQUETE_NIPC_CABECERA));
		if ((nbytes = recv(socket, cabecera, sizeof(PAQUETE_NIPC_CABECERA), MSG_WAITALL)) <= 0)
		{
			if(config.loguear == 1)
			{
				int pid = getpid();
				logMessage("obtenerBloque",pid,gettid(),2,"La cabecera recibida no es correcta.");
			}
		}
		else
		{
			if(cabecera->type != PAYOK)
			{
				if(config.loguear == 1)
				{
					int pid = getpid();
					logMessage("obtenerBloque",pid,gettid(),2,"Error al escribir en ppd/raid.");
				}
			}
		}


		if ((nbytes = recv(socket, cabecera, sizeof(PAQUETE_NIPC_CABECERA), MSG_WAITALL)) <= 0)
		{
			if(config.loguear == 1)
			{
				int pid = getpid();
				logMessage("obtenerBloque",pid,gettid(),2,"La cabecera recibida no es correcta.");
			}
		}
		else
		{
			if(cabecera->type != PAYOK)
			{
				if(config.loguear == 1)
				{
					int pid = getpid();
					logMessage("obtenerBloque",pid,gettid(),2,"Error al escribir en ppd/raid.");
				}
			}
		}

		free(cabecera);
		free(paq);
		free(mensaje);
		free(pedido);
		cerrarConexion(socket);
	}
	else
	{
		//todo loguear error
	}

}


int32_t calcularPrimerBloqueDeCluster(int32_t numCluster)
{
	int32_t numSector;
	numSector = *bs.rsvdseccnt + *bs.numfats * GET_32BIT_WORD(bs.fatsz32, 0) + ((numCluster -2) * *bs.secperclus);
	return (int32_t)(numSector/SECPERBLOQ);
}

int32_t calcularBloqueSegunByte(int32_t numByte)
{
	int32_t numBloque;
	int32_t bytesxbloq = BYTESPERSEC * SECPERBLOQ;
	numBloque = abs (numByte / bytesxbloq);
	return numBloque;
}


//Hace la conexion al ppd/raid, hace el handshake y devuelve el socket listo para usar
int crearConexion()
{
	int32_t re = 1;

	while(re == 1)
	{
		pthread_mutex_lock(&semaforoCantidadConexion);
		if(conexionesAbiertas< cantidadConexiones)
		{

			conexionesAbiertas++;
			pthread_mutex_unlock(&semaforoCantidadConexion);
			re = 0;

			int32_t handshakeOK = 0;
			int32_t reintentar = 1;
			int32_t n;
			char dir[100];
			char command[20];
			int32_t sd = 0;
			sd = conectarPPDRaid(sd);
			/*--------HANDSHAKE  -------------------------------*/
			while(handshakeOK != 1 && reintentar == 1)
			{
				PAQUETE_NIPC_CABECERA paq;
				paq.type = HANDSHAKE;
				paq.payloadlength = 0;

				send(sd,&paq,sizeof(PAQUETE_NIPC_CABECERA),0);

				PAQUETE_NIPC_CABECERA *response = (PAQUETE_NIPC_CABECERA*)malloc(sizeof(PAQUETE_NIPC_CABECERA));

				if (n = recv(sd,response,sizeof(PAQUETE_NIPC_CABECERA),0) != 0)
				{
					if (response->type == PAYFALLO)
					{
						printf("Fallo en el handshake\n ¿Desea reintentar?" );
						gets(dir);
						sscanf(dir, "%s", command);
						if(strstr(command, "SI") || strstr(command, "Si")|| strstr(command, "si"))
						{
							reintentar = 1;
							handshakeOK = 0;
						}
						else
						{
							reintentar = 0;
							handshakeOK = 0;

							pthread_mutex_lock(&semaforoCantidadConexion);
							conexionesAbiertas--;
							pthread_mutex_unlock(&semaforoCantidadConexion);

							close(sd);
							return -1;
							//break;
						}
						//break;
					}
					else if (response->type == PAYOK)
					{
						//printf("Hecho el handshake, socket abierto y a la espera \n");
						handshakeOK = 1;
						reintentar = 0;
						return sd;
						//break;
					}
				}

				free(response);
			}
		}
		else
		{
			pthread_mutex_unlock(&semaforoCantidadConexion);
			//NO HAY CONEXIONES DISPONIBLS
			re = 1;
		}
	}


	/*------------------ HECHO EL HANDSHAKE-----------------------*/

}

int32_t cerrarConexion(int sd)
{
	pthread_mutex_lock(&semaforoCantidadConexion);
	conexionesAbiertas--;
	pthread_mutex_unlock(&semaforoCantidadConexion);

	close(sd);
	//todo restar 1 a las conexiones activas
}
int conectarPPDRaid (int sd)
{
	int32_t re = 0;
	while(re == 0)
	{
		struct sockaddr_in socketInfo;
		if ((sd = socket(AF_INET, SOCK_STREAM, 0)) > 0)
		{
			socketInfo.sin_family = AF_INET;
			socketInfo.sin_addr.s_addr = inet_addr(config.ip);
			socketInfo.sin_port = htons(atoi(config.tcp));
			if (connect(sd, (struct sockaddr*)&socketInfo, sizeof(socketInfo)) == 0)
			{
				//printf("Conectado!\n");
				logMessage("Conexiones", getpid(), gettid(),0, "Se ha conectado al servidor con exito");
				re = 1;

			}
			else
			{
				perror("connect");
				char conversion[15];
				sprintf(conversion, "%d", sd);
				puts(conversion);
				re = 0;
				if(config.loguear== 1)
				{
					int pid = getpid();
					logMessage("connect",pid,gettid(),2,"Error en el connect.");
				}
				close(sd);
			}
		}
		else
		{
			re = 0;
			close(sd);
			//sd = -1;
			perror("socket");
			if(config.loguear== 1)
			{
				int pid = getpid();
				logMessage("connect",pid,gettid(),2,"Error al crear el socket.");
			}
		}
	}
	return sd;
}

